package xm.erzhan.controllers;

import org.json.JSONException;
import xm.erzhan.conf.ResourcesConf.ResourceMainConf;
import xm.erzhan.models.ResourceEntity;
import xm.erzhan.models.responseModels.NormRes;
import xm.erzhan.models.responseModels.ResourceRes;
import xm.erzhan.utils.Code;
import xm.erzhan.utils.ResourceEnum;
import xm.erzhan.utils.Utils;

import java.util.*;

public class ResourceController {

    final static int MAX_COUNT = 2100000000;

    static private ResourceController resourceControllerIns;
    private List<ResourceEntity> resourceEntities;

    /**
     * get resource entity by player id
     *
     * @param playerId
     * @return NormRes Object
     */
    public ResourceRes getResourceEntitiesByPlayerId(int playerId) {
        ResourceRes resourceRes = null;
        ResourceEntity resourceEntity = null;

        if (this.resourceEntities != null) {
            Iterator<ResourceEntity> iterator = this.resourceEntities.iterator();

            ResourceEntity resourceItem;
            while (iterator.hasNext()) {
                resourceItem = iterator.next();
                if (resourceItem.getPlayerId() == playerId) {
                    resourceEntity = resourceItem;
                    break;
                }
            }

            resourceRes = new ResourceRes(Code.CodeEnum.getCodeByType("OK"), "", resourceEntity);

            return resourceRes;
        }

        return resourceRes;
    }

    public ResourceEntity getResourceEntitieByPlayerId(int playerId) {
        ResourceEntity resourceEntity = null;

        if (this.resourceEntities != null) {
            Iterator<ResourceEntity> iterator = this.resourceEntities.iterator();

            ResourceEntity resourceItem;
            while (iterator.hasNext()) {
                resourceItem = iterator.next();
                if (resourceItem.getPlayerId() == playerId) {
                    resourceEntity = resourceItem;
                    break;
                }
            }
        }

        return resourceEntity;
    }


    public void setResourceEntities(ResourceEntity resourceEntity) {

        if (this.resourceEntities == null) {
            this.resourceEntities = new ArrayList<ResourceEntity>();
        }

        this.resourceEntities.add(resourceEntity);
    }


    /**
     * create resource data by resource type and player id
     *
     * @param resourceEntity
     * @param resourceType
     * @return NormRes Object
     */
    public NormRes createResource(ResourceEntity resourceEntity, String resourceType) throws JSONException {
        NormRes normRes;

        // check player warehouse info
        // 1.get warehouse info
        Map warehouseMap = Utils.jsonToMap(resourceEntity.getResourceMap());
        int gold = Integer.parseInt(warehouseMap.get("gold").toString());


        // 2.get resource conf info
        ResourceMainConf resourceMap = ResourceMainConf.getResourceByType(resourceType, 1);


        // 3.check cost
        int warehouseFood = Integer.parseInt(warehouseMap.get("food").toString());
        warehouseFood = warehouseFood - resourceMap.costFood;
        if (warehouseFood < 0) {
            normRes = new NormRes(Code.CodeEnum.getCodeByType("RESOURCE_FOOD_LACK"), "food lack");
            return normRes;
        }

        int warehouseMine = Integer.parseInt(warehouseMap.get("mine").toString());
        warehouseMine = warehouseMine - resourceMap.costSlime;
        if (warehouseMine < 0) {
            normRes = new NormRes(Code.CodeEnum.getCodeByType("RESOURCE_MINE_LACK"), "mine lack");
            return normRes;
        }

        int warehouseSteel = Integer.parseInt(warehouseMap.get("steel").toString());
        warehouseSteel = warehouseSteel - resourceMap.costSteel;
        if (warehouseSteel < 0) {
            normRes = new NormRes(Code.CodeEnum.getCodeByType("RESOURCE_STEEL_LACK"), "steel lack");
            return normRes;
        }

        int warehouseOil = Integer.parseInt(warehouseMap.get("oil").toString());
        warehouseOil = warehouseOil - resourceMap.costOil;
        if (warehouseOil < 0) {
            normRes = new NormRes(Code.CodeEnum.getCodeByType("RESOURCE_OIL_LACK"), "oil lack");
            return normRes;
        }


        // set warehouseEntity
        HashMap warehouseMapTem = new HashMap();
        warehouseMapTem.put("food", warehouseFood);
        warehouseMapTem.put("mine", warehouseMine);
        warehouseMapTem.put("steel", warehouseSteel);
        warehouseMapTem.put("oil", warehouseOil);
        warehouseMapTem.put("gold", gold);

        resourceEntity.setResourceMap(Utils.mapToJson(warehouseMapTem));

        Map map = null;
        if (resourceEntity.getResourceBuildingsMap() == null) {
            map = new HashMap();
        } else {
            map = Utils.jsonToMap(resourceEntity.getResourceBuildingsMap());
        }

        String valueStr = (String) map.get(resourceType);

        if (valueStr == null) {

            int key = map.size();
            String keyStr = String.valueOf(key);

            Map valueMap = new HashMap();
            Long nowTime = Utils.getTimeNow();

            valueMap.put("resourceType", resourceType);
            valueMap.put("level", 1);
            valueMap.put("buildStartTime", nowTime);
            valueMap.put("costSec", resourceMap.costSec);

            if (resourceMap.costSec == 0) {
                valueMap.put("buildStatus", 1);
                valueMap.put("leftTime", 0);
            } else {
                valueMap.put("buildStatus", 0);
                valueMap.put("leftTime", resourceMap.costSec);
            }

            map.put(keyStr, valueMap);

            String resourceStr = Utils.mapToJson(map);

            resourceEntity.setResourceBuildingsMap(resourceStr);

            HashMap mapRes = new HashMap();
            mapRes.put("resource", resourceStr);
            normRes = new NormRes(Code.CodeEnum.getCodeByType("OK"), mapRes);

            return normRes;
        }

        int key = map.size();
        String keyStr = String.valueOf(key);

        Map valueMap = new HashMap();
        Long nowTime = Utils.getTimeNow();

        valueMap.put("resourceType", resourceType);
        valueMap.put("level", 1);
        valueMap.put("buildStartTime", nowTime);

        if (resourceMap.costSec == 0) {
            valueMap.put("buildStatus", 1);
            valueMap.put("leftTime", 0);
        } else {
            valueMap.put("buildStatus", 0);
            valueMap.put("leftTime", resourceMap.costSec);
        }


        map.put(keyStr, valueMap);
        String resourceStr = Utils.mapToJson(map);

        resourceEntity.setResourceBuildingsMap(resourceStr);

        HashMap mapRes = new HashMap();
        map.put("resource", resourceStr);
        normRes = new NormRes(Code.CodeEnum.getCodeByType("OK"), mapRes);

        return normRes;
    }

    public String addProdPower(Map map, String resourceType, int productConfVal) {

        String valueStr = (String) map.get(ResourceEnum.getValueByType(resourceType));

        int value = new Integer(valueStr);

        map.put(ResourceEnum.getValueByType(resourceType), value + productConfVal);

        String productPowerStr = Utils.mapToJson(map);

        return productPowerStr;

    }

    public String getResourceBuildingsMap(ResourceEntity resourceEntity) throws JSONException {
        String resourceBuildingsMap = resourceEntity.getResourceBuildingsMap();

        if (resourceBuildingsMap == null) {
            return null;
        }


        Map map = Utils.jsonToMap(resourceBuildingsMap);

        Long nowTime = Utils.getTimeNow();

        Iterator iterator = map.keySet().iterator();

        String key;
        while (iterator.hasNext()) {
            key = (String) iterator.next();

            String valMapStr = (String) map.get(key);

            Map valMap = Utils.jsonToMap(valMapStr);

            int buildStatus = Integer.parseInt(valMap.get("buildStatus").toString());

            if (buildStatus == 0) {
                Long leftTime = Long.parseLong(valMap.get("leftTime").toString());
                Long buildStartTime = Long.parseLong(valMap.get("buildStartTime").toString());

                Long leftTimeAft = nowTime - buildStartTime;
                if (leftTimeAft >= leftTime) {
                    valMap.put("buildStatus", 1);
                    valMap.put("leftTime", 0);

                        String resourceType = (String) valMap.get("resourceType");

                    // get resource conf info
                    ResourceMainConf resourceMap = ResourceMainConf.getResourceByType(resourceType, Integer.parseInt(valMap.get("level").toString()));

                    // add product power
                    Map productPowerMap = Utils.jsonToMap(resourceEntity.getProductPowerMap());
                    String prodPowerStr = this.addProdPower(productPowerMap, resourceType, resourceMap.product);

                    resourceEntity.setProductPowerMap(prodPowerStr);

                } else {

                    Long costSec = Long.parseLong(valMap.get("costSec").toString());
                    valMap.put("leftTime", costSec - leftTimeAft);
                }

                map.put(key, Utils.mapToJson(valMap));
            }

        }

        return Utils.mapToJson(map);

    }

    public String getResourceBuildingsStatus(String resourceBuildingsMapStr) throws JSONException {

        if (resourceBuildingsMapStr == null) {
            return null;
        }

        Map resourceBuildingsMap = Utils.jsonToMap(resourceBuildingsMapStr);

        int inBuildCount = 0;
        int buildCompleteCount = 0;
        int canBuildCount = resourceBuildingsMap.keySet().size();

        Iterator iterator = resourceBuildingsMap.keySet().iterator();

        String key;
        while (iterator.hasNext()) {

            key = (String) iterator.next();
            String valMapStr = (String) resourceBuildingsMap.get(key);
            Map valMap = Utils.jsonToMap(valMapStr);

            int buildStatus = Integer.parseInt(valMap.get("buildStatus").toString());
            if (buildStatus == 0) {
                inBuildCount ++;
            } else if (buildStatus == 1) {
                buildCompleteCount ++;
            }
        }

        Map resMap = new HashMap();
        resMap.put("inBuildCount", inBuildCount);
        resMap.put("buildCompleteCount", buildCompleteCount);
        resMap.put("canBuildCount", canBuildCount);

        return Utils.mapToJson(resMap);
    }

    public void setAllResourceProduction(ResourceEntity resourceEntity) throws JSONException {

        Long lastUpdateTime = resourceEntity.getLastUpdateTime();
        Long nowTime = Utils.getTimeNow();
        Long differentTime = Long.parseLong(String.valueOf(Math.round((nowTime - lastUpdateTime) / 3600)));

        // 1.get warehouse info
        Map warehouseMap = Utils.jsonToMap(resourceEntity.getResourceMap());

        int food = Integer.parseInt(warehouseMap.get("food").toString());
        int steel = Integer.parseInt(warehouseMap.get("steel").toString());
        int oil = Integer.parseInt(warehouseMap.get("oil").toString());
        int mine = Integer.parseInt(warehouseMap.get("mine").toString());

        Map<String, Integer> resourceProductMap = new HashMap<String, Integer>();
        resourceProductMap.put("farmland", 0);
        resourceProductMap.put("steelmill", 0);
        resourceProductMap.put("oilfield", 0);
        resourceProductMap.put("mine", 0);


        // 2.get resource conf info
        ResourceMainConf resourceMainConf = null;

        // 3.get resourceBuildings info
        Map resourceBuidingsMap = Utils.jsonToMap(resourceEntity.getResourceBuildingsMap());

        Iterator iterator = resourceBuidingsMap.keySet().iterator();

        String key;
        while (iterator.hasNext()) {
            key = (String) iterator.next();

            String valMapStr = (String) resourceBuidingsMap.get(key);

            Map valMap = Utils.jsonToMap(valMapStr);

            String resourceType = valMap.get("resourceType").toString();
            int lv = Integer.parseInt(valMap.get("level").toString());
            resourceMainConf = ResourceMainConf.getResourceByType(resourceType, lv);

            int productVal = resourceProductMap.get(resourceType);
            productVal += resourceMainConf.product;
            resourceProductMap.put(resourceType, productVal);


        }


        int addFood = (int) (resourceProductMap.get("farmland") * differentTime);
        int addSteel = (int) (resourceProductMap.get("steelmill") * differentTime);
        int addOil = (int) (resourceProductMap.get("oilfield") * differentTime);
        int addMine = (int) (resourceProductMap.get("mine") * differentTime);

        if (addFood < 0 || addFood > MAX_COUNT) addFood = 0;
        if (addSteel < 0 || addSteel > MAX_COUNT) addSteel = 0;
        if (addOil < 0 || addOil > MAX_COUNT) addOil = 0;
        if (addMine < 0 || addMine > MAX_COUNT) addMine = 0;

        food += addFood;
        steel += addSteel;
        oil += addOil;
        mine += addMine;

        warehouseMap.put("food", food);
        warehouseMap.put("steel", steel);
        warehouseMap.put("oil", oil);
        warehouseMap.put("mine", mine);

        resourceEntity.setResourceMap(Utils.mapToJson(warehouseMap));

        if (differentTime > 0) {
            resourceEntity.setLastUpdateTime(nowTime);
        }
    }

    public Map createBuilding(ResourceEntity resourceEntity, String buildingType) throws JSONException {
        Map resMap = new HashMap();

        // check player warehouse info
        // 1.get warehouse info
        Map warehouseMap = Utils.jsonToMap(resourceEntity.getResourceMap());
        int gold = Integer.parseInt(warehouseMap.get("gold").toString());


        // 2.get resource conf info
        ResourceMainConf resourceMap = ResourceMainConf.getResourceByType(buildingType, 1);


        // 3.check cost
        int warehouseFood = Integer.parseInt(warehouseMap.get("food").toString());
        warehouseFood = warehouseFood - resourceMap.costFood;
        if (warehouseFood < 0) {

            resMap.put("code", Code.CodeEnum.getCodeByType("RESOURCE_FOOD_LACK"));
            resMap.put("msg", "food lack");

            return resMap;
        }

        int warehouseMine = Integer.parseInt(warehouseMap.get("mine").toString());
        warehouseMine = warehouseMine - resourceMap.costSlime;
        if (warehouseMine < 0) {

            resMap.put("code", Code.CodeEnum.getCodeByType("RESOURCE_MINE_LACK"));
            resMap.put("msg", "mine lack");

            return resMap;
        }

        int warehouseSteel = Integer.parseInt(warehouseMap.get("steel").toString());
        warehouseSteel = warehouseSteel - resourceMap.costSteel;
        if (warehouseSteel < 0) {

            resMap.put("code", Code.CodeEnum.getCodeByType("RESOURCE_STEEL_LACK"));
            resMap.put("msg", "steel lack");

            return resMap;
        }

        int warehouseOil = Integer.parseInt(warehouseMap.get("oil").toString());
        warehouseOil = warehouseOil - resourceMap.costOil;
        if (warehouseOil < 0) {

            resMap.put("code", Code.CodeEnum.getCodeByType("RESOURCE_OIL_LACK"));
            resMap.put("msg", "oil lack");

            return resMap;
        }


        // set warehouseEntity
        HashMap warehouseMapTem = new HashMap();
        warehouseMapTem.put("food", warehouseFood);
        warehouseMapTem.put("mine", warehouseMine);
        warehouseMapTem.put("steel", warehouseSteel);
        warehouseMapTem.put("oil", warehouseOil);
        warehouseMapTem.put("gold", gold);

        resourceEntity.setResourceMap(Utils.mapToJson(warehouseMapTem));



        // set building info


        return resMap;

    }


    /**
     * ResourceController shared
     *
     * @return ResourceController instance
     */
    static public ResourceController resourceControllerShared() {
        if (resourceControllerIns == null) {
            resourceControllerIns = new ResourceController();
        }

        return resourceControllerIns;
    }
}
